'use strict';

const crypto = require('crypto');
const utility = require('./utility');
const dbError = require('./dbError');
const mongoose = require('mongoose');
const dbConfig = require('../config.json').dbConfig;
const logger = require('./logutility').logger('dbutility');
const db = mongoose.connect(dbConfig.path);

const DBInsertError = dbError.DBInsertError;
const DBDeleteError = dbError.DBDeleteError;
const DBUpdateError = dbError.DBUpdateError;
const DBSearchError = dbError.DBSearchError;

/**
 * 快递员信息文档模式
 */
const couSchema = new mongoose.Schema({
    couName: { type: String },//快递员姓名
    couTel: { type: String },//快递员电话（登陆账号）
    couCmp: { type: String },//快递员所属快递公司（若所属快递公司为9999，则为管理员账号）
    couPwd: { type: String }//快递员登陆密码
});

/**
 * 快递信息文档模式
 */
const expSchema = new mongoose.Schema({
    expNo: { type: String },//快递编号
    expReName: { type: String },//快递收件人姓名
    expReTel: { type: String },//快递收件人电话
    expPay: { type: Number },//快递代收费用
    expCouTel: { type: String },//快递投递人账号
    expCabinetNo: { type: String },//投递入柜快递柜号
    expSmsStatus: { type: String },//快递短信发送状态
    expStatus: { type: String },//快递状态
    expInDate: { type: Date },//快递入柜时间
    expOutDate: { type: Date }//快递出柜时间
});

/**
 * 快递柜信息文档模式
 */
const cabSchema = new mongoose.Schema({
    cabNo: { type: String },//快递柜编号
    cabType: { type: String },//快递柜型号
    cabInUse: { type: Boolean },//快递柜使用状态
    cabPwd: { type: String },//开柜密码
    cabPortName: { type: String },//串口名称
    cabOpenCmd: { type: String },//开柜命令
    cabCheckCmd: { type: String },//检测命令
    cabOpenStatus: { type: String }//打开状态字符串
});

/**
 * 信息记录文档模式
 */
const msgSchema = new mongoose.Schema({
    expNo: { type: String },//快递编号
    msgId: { type: String },//信息ID
    msgStatus: { type: String },//信息发送状态(发送成功,发送失败)
    msgRepeat: { type: Number }//信息重发次数
});

/**
 * 根据快递编号取得快递记录
 * 
 * @param {string}expNo 快递单号
 * @return {Promise}
 */
expSchema.statics.getExpByExpNo = function(expNo) {
    return new Promise((resolve, reject) => {
        let searchCondition = { expNo };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getExpByExpNo', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 取得快递记录
 * 
 * @param {string}expNo 快递单号
 * @param {string}expCouTel 快递投递人账号
 * @return {Promise}
 */
expSchema.statics.getExp = function(expNo, expCouTel) {
    return new Promise((resolve, reject) => {
        let searchCondition = { expNo, expCouTel };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getExp', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 根据电话号码后四位取得快递记录（用于快速录入）
 * 
 * @param {string}tel4 电话号码后四位
 * @return {Promise}
 */
expSchema.statics.getReTelNameByTel4 = function(tel4) {
    return new Promise((resolve, reject) => {
        let regExp = new RegExp(tel4 + '$');
        let searchCondition = { expReTel: { $regex: regExp } };
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getReTelNameByTel4', searchCondition, err));
            } else {
                resolve(doc);
            }
        })
    })
}

/**
 * 插入快递记录
 * 
 * @param {string}expNo 快递单号
 * @param {string}expReName 快递收件人姓名
 * @param {string}expReTel 快递收件人电话
 * @param {string}expPay 快递代收费用
 * @param {string}expCouTel 快递投递人账号
 * @return {Promise}
 */
expSchema.statics.insertExp = function(expNo, expReName, expReTel, expPay, expCouTel) {
    return new Promise((resolve, reject) => {
        let expStatus = '未投递';
        let expSmsStatus = '未发送';
        let insertData = { expNo, expReName, expReTel, expPay, expCouTel, expStatus, expSmsStatus };
        this.create(insertData, function(err, doc) {
            if (err) {
                reject(new DBInsertError('insertExp', insertData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 更新快递记录
 * 
 * @param {string}expNo 快递单号
 * @param {string}expCouTel 快递投递人账号
 * @param {string}expReName 快递收件人姓名
 * @param {string}expReTel 快递收件人电话
 * @param {string}expPay 快递代收费用
 * @return {Promise}
 */
expSchema.statics.updateExp = function(expNo, expCouTel, expReName, expReTel, expPay) {
    return new Promise((resolve, reject) => {
        let updateCondition = { expNo, expCouTel };
        let updateData = { expReName, expReTel, expPay };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateExp', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 删除快递记录
 * 
 * @param {string}expNo 快递单号
 * @param {string}expCouTel 快递投递人账号
 * @return {Promise}
 */
expSchema.statics.deleteExp = function(expNo, expCouTel) {
    return new Promise((resolve, reject) => {
        let deleteCondition = { expNo, expCouTel };
        this.remove(deleteCondition, function(err, doc) {
            if (err) {
                reject(new DBDeleteError('deleteExp', deleteCondition, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得没有进行投递的所有快递记录
 * 
 * @param {string}expCouTel 快递投递人账号
 * @return {Promise}
 */
expSchema.statics.getExpNeedDlv = function(expCouTel) {
    return new Promise((resolve, reject) => {
        let expStatus = '未投递';
        let searchCondition = { expCouTel, expStatus };
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getExpNeedDlv', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 取得最近三天的所有已投递快递以及全部未投递快递的投递记录
 * 
 * @param {string}expCouTel 快递投递人账号
 * @return {Promise}
 */
expSchema.statics.getLatestExpAll = function(expCouTel) {
    return new Promise((resolve, reject) => {
        let threeDaysAgo = new Date((new Date()).getTime() - 1000 * 60 * 60 * 24 * 3);
        let searchCondition = { '$or': [{ expCouTel, expInDate: { '$gte': threeDaysAgo } }, { expCouTel, expInDate: null }] };
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getLatestExpAll', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 更新快递状态到‘已投递’
 * 
 * @param {string}expNo 快递单号
 * @param {string}expCouTel 快递投递人账号
 * @param {string}expCabinetNo 投递入柜快递柜号
 * @return {Promise}
 */
expSchema.statics.updateExpToDlved = function(expNo, expCouTel, expCabinetNo) {
    return new Promise((resolve, reject) => {
        let expInDate = new Date();
        let expStatus = '已投递';
        let updateCondition = { expNo, expCouTel };
        let updateData = { expCabinetNo, expInDate, expStatus };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateExpToDlved', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 更新快递状态到‘已取件’
 * 
 * @param {string}expCabinetNo 投递入柜快递柜号
 * @return {Promise}
 */
expSchema.statics.updateExpToTaked = function(expCabinetNo) {
    return new Promise((resolve, reject) => {
        let expOutDate = new Date();
        let expStatus = '已取件';
        let updateCondition = { expCabinetNo, expStatus: '已投递' };
        let updateData = { expOutDate, expStatus };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateExpToTaked', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得所有快递记录
 */
expSchema.statics.getExpAll = function() {
    return new Promise((resolve, reject) => {
        this.find({}, function(err, doc) {
            if (err) {
                reject(err);
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 插入信息记录
 * 
 * @param {string}expNo 快递单号
 * @return {Promise}
 */
msgSchema.statics.insertMsg = function(expNo) {
    return new Promise((resolve, reject) => {
        let insertData = { expNo };
        this.create(insertData, function(err, doc) {
            if (err) {
                reject(new DBInsertError('insertMsg', insertData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 根据快递柜编号取出未使用的快递柜记录
 * 
 * @param {string}cabType 快递柜型号
 * @return {Promise}
 */
cabSchema.statics.getCabByCabTypeNotInUse = function(cabType) {
    return new Promise((resolve, reject) => {
        let cabInUse = false;
        let searchCondition = { cabType, cabInUse };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getCabByCabTypeNotInUse', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 根据快递柜编号取得快递柜记录
 * 
 * @param {string}cabNo 快递柜编号
 * @return {Promise}
 */
cabSchema.statics.getCabByCabNo = function(cabNo) {
    return new Promise((resolve, reject) => {
        let searchCondition = { cabNo };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getCabByCabNo', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 根据快递柜密码取得快递柜记录
 * 
 * @param {string}cabPwd 开柜密码
 * @return {Promise}
 */
cabSchema.statics.getCabByCabPwd = function(cabPwd) {
    return new Promise((resolve, reject) => {
        let searchCondition = { cabPwd };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getCabByCabPwd', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}


/**
 * 取出所有正在使用的快递柜信息
 * 
 * @return {Promise}
 */
cabSchema.statics.getAllCabInUse = function() {
    return new Promise((resolve, reject) => {
        let searchCondition = { cabInUse: true };
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getAllCab', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 更新快递柜状态到‘使用中’
 * 
 * @param {string}cabNo 快递柜编号
 * @param {string}cabPwd 开柜密码
 * @return {Promise}
 */
cabSchema.statics.updateCabToInUse = function(cabNo, cabPwd) {
    return new Promise((resolve, reject) => {
        let cabInUse = true;
        let updateCondition = { cabNo };
        let updateData = { cabInUse, cabPwd };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateCabToInUse', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 更新快递状态到‘未使用’
 * 
 * @param {string}cabNo 快递柜编号
 * @return {Promise}
 */
cabSchema.statics.updateCabToNotInUse = function(cabNo) {
    return new Promise((resolve, reject) => {
        let cabInUse = false;
        let cabPwd = null;
        let updateCondition = { cabNo };
        let updateData = { cabInUse, cabPwd };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateCabToNotInUse', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得用户权限
 * 
 * @param {string}userTel 用户账号
 * @param {string}userPwd 用户密码
 * @return {Promise}
 */
couSchema.statics.getUserAuth = function(userTel, userPwd) {
    return new Promise((resolve, reject) => {
        let couTel = userTel;
        let couPwd = userPwd;
        let searchCondition = { couTel, couPwd };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getUserAuth', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 插入新的快递员记录
 * 
 * @param {string}couName 快递员姓名
 * @param {string}couTel 快递员电话（登陆账号）
 * @param {string}couCmp 快递员所属快递公司（若所属快递公司为9999，则为管理员账号）
 * @return {Promise}
 */
couSchema.statics.insertCou = function(couName, couTel, couCmp) {
    return new Promise((resolve, reject) => {
        let insertData = { couName, couTel, couCmp };
        this.create(insertData, function(err, doc) {
            if (err) {
                reject(new DBInsertError('insertCou', insertData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 删除快递员记录
 * 
 * @param {string}couTel 快递员电话（登陆账号）
 * @return {Promise}
 */
couSchema.statics.deleteCou = function(couTel) {
    return new Promise((resolve, reject) => {
        let deleteCondition = { couTel };
        this.remove(deleteCondition, function(err, doc) {
            if (err) {
                reject(new DBDeleteError('deleteCou', deleteCondition, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 更新快递员记录
 * 
 * @param {string}couTel 快递员电话（登陆账号）
 * @param {string}couName 快递员姓名
 * @param {string}couCmp 快递员所属快递公司（若所属快递公司为9999，则为管理员账号）
 * @return {Promise}
 */
couSchema.statics.updateCou = function(couTel, couName, couCmp) {
    return new Promise((resolve, reject) => {
        let updateCondition = { couTel };
        let updateData = { couName, couCmp };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateCou', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 更新快递员登陆密码
 * 
 * @param {string}couTel 快递员电话（登陆账号）
 * @param {string}couPwd 快递员登陆密码
 * @return {Promise}
 */
couSchema.statics.updateCouPwd = function(couTel, couPwd) {
    return new Promise((resolve, reject) => {
        let updateCondition = { couTel };
        let updateData = { couPwd };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new DBUpdateError('updateCouPwd', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得所有的快递员记录
 * 
 * @return {Promise}
 */
couSchema.statics.getCouAll = function() {
    return new Promise((resolve, reject) => {
        let searchCondition = {};
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getCouAll', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 检查快递员是否存在
 * 
 * @param {string}couTel 快递员电话（登陆账号）
 * @return {Promise}
 */
couSchema.statics.getCouByCouTel = function(couTel) {
    return new Promise((resolve, reject) => {
        let searchCondition = { couTel };
        this.findOne(searchCondition, function(err, doc) {
            if (err) {
                reject(new DBSearchError('getCouByCouTel', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 快递员信息文档模型
 */
const couModel = db.model('cou', couSchema);

/**
 * 快递信息文档模型
 */
const expModel = db.model('exp', expSchema);

/**
 * 快递柜信息文档模型
 */
const cabModel = db.model('cab', cabSchema);

/**
 * 信息记录文档模型
 */
const msgModel = db.model('msg', msgSchema);

exports.couModel = couModel;
exports.expModel = expModel;
exports.cabModel = cabModel;
exports.msgModel = msgModel;